---
title: Server Integration
---

The Cloud Messaging module provides the tools required to enable you to send custom messages directly from your own servers.
For example, you could send an FCM message to a specific device when a new chat message is saved to your database and display
a notification, or update local device storage, so the message is instantly available.

Firebase provides a number of SDKs in different languages such as [Node.JS](https://www.npmjs.com/package/firebase-admin),
[Java](https://firebase.google.com/docs/reference/admin/java/reference/com/google/firebase/messaging/package-summary),
[Python](https://firebase.google.com/docs/reference/admin/python/firebase_admin.messaging),
[C#](https://firebase.google.com/docs/reference/admin/dotnet/namespace/firebase-admin/messaging) and
[Go](https://godoc.org/firebase.google.com/go/messaging). It also supports sending messages over
[HTTP](https://firebase.google.com/docs/reference/fcm/rest/v1/projects.messages). These methods allow you to send messages
directly to your user's devices via the FCM servers.

## Device tokens

To send a message to a device, you must access its unique token.
A token is automatically generated by the device and can be accessed using the Cloud Messaging module.
The token should be saved inside your systems data-store and should be easily accessible when required.

The examples below use a Cloud Firestore database to store and manage the tokens, and Firebase Authentication to manage the users identity.
You can however use any datastore or authentication method of your choice.

> If using iOS, ensure you have completed the [setup](apple-integration.mdx) & [requested user permission](permissions.mdx) before trying to receive messages!

### Saving tokens

Once your application has started, you can call the `getToken` method on the Cloud Messaging module to get the unique
device token (if using a different push notification provider, such as Amazon SNS, you will need to call `getAPNSToken` on iOS):

```dart
Future<void> saveTokenToDatabase(String token) async {
  // Assume user is logged in for this example
  String userId = FirebaseAuth.instance.currentUser.uid;

  await FirebaseFirestore.instance
    .collection('users')
    .doc(userId)
    .update({
      'tokens': FieldValue.arrayUnion([token]),
    });
}

class Application extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => _Application();
}

class _Application extends State<Application> {
  String _token;

  @override
  void initState() async {
    super.initState();
    // Get the token each time the application loads
    String token = await FirebaseMessaging.instance.getToken();

    // Save the initial token to the database
    await saveTokenToDatabase(token);

    // Any time the token refreshes, store this in the database too.
    FirebaseMessaging.instance.onTokenRefresh.listen(saveTokenToDatabase);
  }

  @override
  Widget build(BuildContext context) {
    return Text("...");
  }
}
```

The above code snippet has a single purpose; storing the device FCM token on a remote database. When your application first initializes, the
users FCM token is fetched and stored in a database (Cloud Firestore in this example). If the token is refreshed at anypoint whilst your application
is open, the new token is also stored on the database.

It is important to remember a user can have many tokens (from multiple devices, or token refreshes), therefore we use `FieldValue.arrayUnion` to store
new tokens. When a message is sent via an admin SDK, invalid/expired tokens will throw an error allowing you to then remove them from the database.

### Using tokens

With the tokens stored in a secure datastore, we now have the ability to send messages via FCM to those devices.

The following example uses the Node.JS `firebase-admin` package to send messages to our devices, however any Firebase Admin SDK can be used.

Imagine our application being similar to Instagram. Users are able to upload pictures, and other users can "like" those pictures.
Each time a post is liked, we want to send a message to the user that uploaded the picture.

The code below simulates a function which is called with all the information required when a picture is liked:

```js
// Node.js e.g via a Firebase Cloud Function
var admin = require("firebase-admin");

// ownerId - who owns the picture someone liked
// userId - id of the user who liked the picture
// picture - metadata about the picture

async function onUserPictureLiked(ownerId, userId, picture) {
  // Get the owners details
  const owner = admin.firestore().collection("users").doc(ownerId).get();

  // Get the users details
  const user = admin.firestore().collection("users").doc(userId).get();

  await admin.messaging().sendToDevice(
    owner.tokens, // ['token_1', 'token_2', ...]
    {
      data: {
        owner: JSON.stringify(owner),
        user: JSON.stringify(user),
        picture: JSON.stringify(picture),
      },
    },
    {
      // Required for background/quit data-only messages on iOS
      contentAvailable: true,
      // Required for background/quit data-only messages on Android
      priority: "high",
    }
  );
}
```

Data-only messages are sent as low priority on both Android and iOS and will not trigger the background handler by default. To enable this
functionality, you must set the "priority" to `high` on Android and enable the `content-available` flag for iOS in the message payload.

The data property can send an object of key-value pairs totaling 4 KB as string values (hence the `JSON.stringify` calls).

Within the application, you can then handle these messages how you see fit:

```dart
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
  Map<String, String> data = message.data;

  Owner owner = Owner.fromMap(jsonDecode(data['owner']));
  User user = User.fromMap(jsonDecode(data['user']));
  Picture picture = Picture.fromMap(jsonDecode(data['picture']));

  print('The user ${user.name} liked your picture "${picture.title}"!');
});
```

Your application code can then handle messages as you see fit; updating local cache, displaying a notification or updating UI. The possibilities are endless!

## Send messages to topics

When devices [subscribe to topics](usage.mdx#subscribing-to-topics), you can send messages without specifying/storing any device tokens.

Using the `firebase-admin` Admin SDK as an example, we can send a message to devices subscribed to a topic:

```js
// Node.js e.g via a Firebase Cloud Function
const admin = require("firebase-admin");

const message = {
  data: {
    type: "warning",
    content: "A new weather warning has been created!",
  },
  topic: "weather",
};

admin
  .messaging()
  .send(message)
  .then((response) => {
    console.log("Successfully sent message:", response);
  })
  .catch((error) => {
    console.log("Error sending message:", error);
  });
```

### Conditional topics

To send a message to a combination of topics, specify a condition, which is a boolean expression that specifies the target topics.
For example, the following condition will send messages to devices that are subscribed to `weather` and either `news` or `traffic`:

```js
const admin = require("firebase-admin");

const message = {
  data: {
    content: "New updates are available!",
  },
  condition: "'weather' in topics && ('news' in topics || 'traffic' in topics)",
};

admin
  .messaging()
  .send(message)
  .then((response) => {
    console.log("Successfully sent message:", response);
  })
  .catch((error) => {
    console.log("Error sending message:", error);
  });
```
